#ifndef __EVENTLOOP_H__
#define __EVENTLOOP_H__

#include "Acceptor.h"
#include "TcpConnection.h"
#include <vector>
#include <sys/epoll.h>
#include <unordered_map>
#include <memory>
#include <functional>
#include <mutex>
#include <sys/eventfd.h>

using std::vector;
using std::unordered_map;
using std::shared_ptr;
using std::function;
using std::mutex;
using std::unique_lock;
using std::cout;
using std::endl;

using TcpConnectionPtr = shared_ptr<TcpConnection>;
using TcpConnectionCallback = function<void(const TcpConnectionPtr&)>;
using Functor = function<void()>;

class EventLoop
{
public:
    EventLoop(Acceptor &acceptor);
    ~EventLoop();
    void loop();
    void unloop();
    void waitEpollFd();
private:
    void handleNewConnection();
    void handleMessage(int fd);
    int createEpollFd();
    void addEpollReadFd(int fd);
    void delEpollReadFd(int fd);
public:
    //三种回调函数在EventLoop类中作为中转(这是三个事件)，在TcpConnection类中调用(这三个事件是与连接相关的)
    void setNewConnectionCallback(TcpConnectionCallback &&cb);  //使用右值引用，因为每次设置是一个临时函数
    void setMessageCallback(TcpConnectionCallback &&cb);
    void setCloseCallback(TcpConnectionCallback &&cb);
public:
    void wakeup(); //封装write(对于eventfd)
    void runInLoop(Functor &&cb); //将"任务"存放在容器中并执行wakeup
private:
    void handleRead();  //封装read函数(对于eventfd)
    int createEventFd(); //
    void doPendingFunctors();   //执行所有"任务"
private:
    int _epfd;  //epoll_create创建的文件描述符  
    vector<struct epoll_event> _evtList;    //存放满足条件的文件描述符的数据结构
    bool _isLooping;        //标识循环是否在运行的标志
    Acceptor& _acceptor;    //因为需要调用其中的accept函数
    unordered_map<int,shared_ptr<TcpConnection>> _conns;    //存放的是文件描述符与连接的键值对
    TcpConnectionCallback _onNewConnectionCb;
    TcpConnectionCallback _onMessageCb;
    TcpConnectionCallback _onCloseCb;

    int _evtfd; //用于通知的fd(当线程池处理完数据后,通知Reactor/EventLoop,Reactor就可将处理好的数据传给客户端)
    vector<Functor> _pendings; //存放"任务"的数据结构，因为线程池处理的任务有多个，
    //所以需要使用容器存储，并且容器被多个线程并发访问，所以需要加锁
    mutex _mutex;
};

#endif
